# 背景

交换机胖模式,因机器内存大小限制,不能随意引用外部插件。为了解决表格内容过长时的显示问题,于是自己实现手动拖动改变列宽功能,提升用户体验。

# 实现逻辑

  1. 首先在原有表格组件中增加配置选项,用来开启表格的列拖动功能,默认false。

  2. 表格配置项中的每列的宽度不能带单位,带单位会导致无法拖动(依据旧组件架构,只能出此下策)。通过改变表头的宽度,使tBody部分自动跟随。

  3. 在获取接口数据后,直接生成固定在顶部的表头,这个表头原本是在第一次滚动时生成的,这个css结构决定了后面的一系列妥协。

生成表头后为其绑定鼠标事件。

鼠标下落事件:

记录拖动元素的位置,宽度信息。特别提醒,位置需要用clientX获取,用x获取的话在IE下可能会不准(因为event.x如果是在relative定位的盒子中,是已该盒子进行计算的,而不是屏幕)。

鼠标移动事件:

保证列宽不为负的情况下,记录拖动后的宽度,并赋给当前元素。为了兼容ie9,需要同时赋值最小宽度。

因表头为了固定在顶部,旧的架构使用了另外一个table,给我们的改动宽度带来了很大的困难。这里在拖动后获取实际内容表格每列的宽度,再赋值给表头,来实现每列的宽度自动适应。

鼠标上事件:

清除数据,延迟100ms后再执行一次调整表头位置,防止快速拖动时导致的错位。

# 源码

/**
 * 设置列宽可拖动
 * @param $tab
 * @private
 */
_setColConfig: function($tab) {
    var me = this;
    if (this.options.changeColWidth) {
        var mainTable = this.$el[0].children[0]
        var table = $tab || mainTable
        var tTD; //用来存储当前更改宽度的Table Cell,避免快速移动鼠标的问题
        for (j = 0; j < table.rows[0].cells.length; j++) {
            table.rows[0].cells[j].onmousedown = function () {
                //记录单元格
                tTD = this;
                if (event.offsetX > tTD.offsetWidth - 10) {
                    tTD.mouseDown = true;
                    tTD.oldX = event.clientX;
                    tTD.oldWidth = tTD.offsetWidth;
                }
            };
            table.rows[0].cells[j].onmousemove = function () {
                //更改鼠标样式
                if (event.offsetX > this.offsetWidth - 10)
                    this.style.cursor = 'col-resize';
                else
                    this.style.cursor = 'default';
                //取出暂存的Table Cell
                if (tTD == undefined) tTD = this;
                //调整宽度
                if (tTD.mouseDown != null && tTD.mouseDown == true) {
                    tTD.style.cursor = 'default';
                    if (tTD.oldWidth + (event.clientX - tTD.oldX) > 0) {
                        var tTdWidth = tTD.oldWidth + (event.clientX - tTD.oldX) + '';
                        tTD.width = tTdWidth
                    }
                    //调整列宽
                    tTD.style.width = tTdWidth + 'px';
                    tTD.style.minWidth = tTdWidth + 'px';
                    tTD.style.cursor = 'col-resize';
                    //调整该列中的每个Cell
                    table = tTD;
                    while (table.tagName != 'TABLE') table = table.parentElement;
                    for (j = 0; j < table.rows.length; j++) {
                        // 改变固定表头的宽度
                        table.rows[j].cells[tTD.cellIndex].width = tTdWidth;
                        table.rows[j].cells[tTD.cellIndex].style.width = tTdWidth + 'px';
                        // 改变主内容表格的宽度
                        if ($tab) {
                            mainTable.rows[j].cells[tTD.cellIndex].width = tTdWidth;
                            mainTable.rows[j].cells[tTD.cellIndex].style.width = tTdWidth + 'px';
                            mainTable.rows[j].cells[tTD.cellIndex].style.minWidth = tTdWidth + 'px';
                        }
                    }
                    if ($tab) {
                        me._setFixTableHeadWidth(table, mainTable)
                    }
                }
            };
            table.rows[0].cells[j].onmouseup = function () {
                //结束宽度调整
                if (tTD == undefined) tTD = this;
                tTD.mouseDown = false;
                tTD.style.cursor = 'default';
                // 结束时再执行一次,防止错位
                if ($tab) {
                    setTimeout(function() {
                        me._setFixTableHeadWidth(table, mainTable)
                    }, 100)
                }
            };
        }
    }
},
/**
 * 根据主内容表格的宽度来设置固定的表头的宽度
 * @param table
 * @param mainTable
 * @private
 */
_setFixTableHeadWidth: function (table, mainTable) {
    for (var k = 0; k < mainTable.rows[0].cells.length; k++) {
        var width = mainTable.rows[0].cells[k].offsetWidth + 'px'
        table.rows[0].cells[k].style.width = width
        table.rows[0].cells[k].style.minWidth = width
    }
},